package com.peng.test.jackson;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ContainerNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import org.junit.jupiter.api.Test;

/**
 * JacksonUtil
 *
 * @author lupeng
 * Created on 2022-03-13
 */
public class JacksonUtil {

    public static void main(String[] args) {
        InputStream inputStream = Thread.currentThread().getContextClassLoader()
                //.getResourceAsStream("test.json");
                .getResourceAsStream("test1.json");
        StringBuilder builder = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        reader.lines().forEach(builder::append);
        String jsonStr = builder.toString();
        System.out.println(jsonStr);
        System.out.println("----------convert-----------");


        JacksonUtil jacksonUtil = new JacksonUtil(jsonStr);
        String convert = jacksonUtil.convert();
        System.out.println(convert);

        System.out.println("-----------deConvert----------");

        String deConvert = jacksonUtil.deConvert(convert);
        System.out.println(deConvert);
    }

    private static final ObjectMapper MAPPER = new ObjectMapper();

    private final Set<String> flagJsonPaths = new HashSet<>();

    private final String needConvertJsonStr;

    public JacksonUtil(String needConvertJsonStr) {
        this.needConvertJsonStr = needConvertJsonStr;
    }

    public String deConvert(String jsonStr) {
        JsonNode jsonNode;
        try {
            jsonNode = MAPPER.readTree(jsonStr);
            deConvertDfs(jsonNode, "$");
            return jsonNode.toString();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private JsonNode deConvertDfs(JsonNode jsonNode, String jsonPath) {
        if (!(jsonNode instanceof ContainerNode)) {
            return jsonNode;
        }
        if (jsonNode instanceof ObjectNode) {
            ObjectNode parent = (ObjectNode) jsonNode;
            Iterator<Map.Entry<String, JsonNode>> fields = parent.fields();
            while (fields.hasNext()) {
                Map.Entry<String, JsonNode> entry = fields.next();
                JsonNode child = entry.getValue();
                String key = entry.getKey();
                String currJsonPath = jsonPath + "." + key;
                JsonNode res = deConvertDfs(child, currJsonPath);
                if (flagJsonPaths.contains(currJsonPath)) {
                    res = TextNode.valueOf(res.toString());
                }
                parent.set(key, res);
            }
            return parent;
        } else if (jsonNode instanceof ArrayNode) {
            String template = jsonPath + "[%s]";
            ArrayNode arrayNode = (ArrayNode) jsonNode;
            for (int i = 0; i < arrayNode.size(); i++) {
                String currJsonPath = String.format(template, i);
                JsonNode old = arrayNode.remove(i);
                JsonNode newObj = deConvertDfs(old, String.format(template, i));
                if (flagJsonPaths.contains(currJsonPath)) {
                    newObj = TextNode.valueOf(newObj.toString());
                }
                arrayNode.insert(i, newObj);
            }
            return arrayNode;
        }
        return jsonNode;
    }

    public String convert() {
        try {
            JsonNode jsonNode = MAPPER.readTree(needConvertJsonStr);
            convertDfs(jsonNode, "$", 0);
            return jsonNode.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private Object convertDfs(JsonNode jsonNode, String jsonPath, int depth) {
        if (jsonNode instanceof ObjectNode) {
            ObjectNode parent = (ObjectNode) jsonNode;
            Iterator<Map.Entry<String, JsonNode>> fields = parent.fields();
            while (fields.hasNext()) {
                Map.Entry<String, JsonNode> entry = fields.next();
                JsonNode child = entry.getValue();
                String key = entry.getKey();
                JsonNode res = (JsonNode) convertDfs(child, jsonPath + "." + key, depth + 1);
                parent.set(key, res);
            }
            return parent;
        } else if (jsonNode instanceof ArrayNode) {
            String template = jsonPath + "[%s]";
            ArrayNode arrayNode = (ArrayNode) jsonNode;
            for (int i = 0; i < arrayNode.size(); i++) {
                JsonNode old = arrayNode.remove(i);
                JsonNode newObj = (JsonNode) convertDfs(old, String.format(template, i), depth + 1);
                arrayNode.insert(i, newObj);
            }
            return arrayNode;
        } else if (jsonNode instanceof TextNode) {
            // 编码过的字符串
            String jsonStr = jsonNode.asText();
            try {
                JsonNode convertJsonNode = MAPPER.readTree(jsonStr);
                flagJsonPaths.add(jsonPath);
                return convertDfs(convertJsonNode, jsonPath, depth);
            } catch (JsonProcessingException e) {
                return TextNode.valueOf(jsonStr);
            }
        }
        return jsonNode;
    }


}
